package com.wangzhenyu.learn.test.android_.picture

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Environment
import com.wangzhenyu.common.util.log.LogUtil
import java.io.File
import java.io.FileInputStream

/*
图片基础知识
ARGB颜色模型：
最常见的颜色模型，设备相关，四种通道，取值均为[0，255]，即转化成二进制位0000 0000 ~ 1111 1111。
A：Alpha (透明度) R：Red (红) G：Green (绿) B：Blue (蓝)
Bitmap概念
Bitmap对象本质是一张图片的内容在手机内存中的表达形式。它将图片的内容看做是由存储数据的有限个像素点组成；
每个像素点存储该像素点位置的ARGB值。每个像素点的ARGB值确定下来，这张图片的内容就相应地确定下来了。
Bitmap：
Bitmap是Android系统中的图像处理的最重要类之一。用它可以获取图像文件信息，进行图像剪切、旋转、缩放等操作，并可以指定格式保存图像文件。
重要函数
public void recycle() // 回收位图占用的内存空间，把位图标记为Dead
public final boolean isRecycled() //判断位图内存是否已释放
public final int getWidth()//获取位图的宽度
public final int getHeight()//获取位图的高度
public final boolean isMutable()//图片是否可修改
public int getScaledWidth(Canvas canvas)//获取指定密度转换后的图像的宽度
public int getScaledHeight(Canvas canvas)//获取指定密度转换后的图像的高度
public boolean compress(CompressFormat format, int quality, OutputStream stream)//按指定的图片格式以及画质，将图片转换为输出流。
format：Bitmap.CompressFormat.PNG或Bitmap.CompressFormat.JPEG
quality：画质，0-100.0表示最低画质压缩，100以最高画质压缩。对于PNG等无损格式的图片，会忽略此项设置。
public static Bitmap createBitmap(Bitmap src) //以src为原图生成不可变得新图像
public static Bitmap createScaledBitmap(Bitmap src, int dstWidth,int dstHeight, boolean filter)//以src为原图，创建新的图像，指定新图像的高宽以及是否可变。
public static Bitmap createBitmap(int width, int height, Config config)创建指定格式、大小的位图
public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height)以source为原图，创建新的图片，指定起始坐标以及新图像的高宽。
BitmapFactory工厂类：
Option 参数类：
public boolean inJustDecodeBounds//如果设置为true，不获取图片，不分配内存，但会返回图片的高度宽度信息。
public int inSampleSize//图片缩放的倍数
public int outWidth//获取图片的宽度值
public int outHeight//获取图片的高度值
public int inDensity//用于位图的像素压缩比
public int inTargetDensity//用于目标位图的像素压缩比（要生成的位图）
public byte[] inTempStorage //创建临时文件，将图片存储
public boolean inScaled//设置为true时进行图片压缩，从inDensity到inTargetDensity
public boolean inDither //如果为true,解码器尝试抖动解码
public Bitmap.Config inPreferredConfig //设置解码器
public String outMimeType//设置解码图像
public boolean inPurgeable//当存储Pixel的内存空间在系统内存不足时是否可以被回收
public boolean inInputShareable //inPurgeable为true情况下才生效，是否可以共享一个InputStream
public boolean inPreferQualityOverSpeed//为true则优先保证Bitmap质量其次是解码速度
public boolean inMutable //配置Bitmap是否可以更改，比如：在Bitmap上隔几个像素加一条线段
public int inScreenDensity //当前屏幕的像素密度
工厂方法:
public static Bitmap decodeFile(String pathName, Options opts) //从文件读取图片
public static Bitmap decodeFile(String pathName)
public static Bitmap decodeStream(InputStream is)//从输入流读取图片 只能用一次，不然会返回null，未知原因
public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts)
public static Bitmap decodeResource(Resources res, int id) //从资源文件读取图片
加载的图片可能会经过缩放，该缩放目前是放在 java 层做的，效率比较低，而且需要消耗 java 层的内存。因此，如果大量使用该接口加载图片，容易导致OOM错误
public static Bitmap decodeResource(Resources res, int id, Options opts)
public static Bitmap decodeByteArray(byte[] data, int offset, int length) //从数组读取图片
public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts)
public static Bitmap decodeFileDescriptor(FileDescriptor fd)//从文件读取文件 与decodeFile不同的是这个直接调用JNI函数进行读取 效率比较高
public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts)
Bitmap.Config inPreferredConfig :
枚举变量 （位图位数越高代表其可以存储的颜色信息越多，图像越逼真，占用内存越大）
public static final Bitmap.Config ALPHA_8 //代表8位Alpha位图 每个像素占用1byte内存
public static final Bitmap.Config ARGB_4444 //代表16位ARGB位图 每个像素占用2byte内存
public static final Bitmap.Config ARGB_8888 //代表32位ARGB位图 每个像素占用4byte内存
public static final Bitmap.Config RGB_565 //代表8位RGB位图 每个像素占用2byte内存

Android中一张图片（BitMap）占用的内存主要和以下几个因数有关：图片长度，图片宽度，单位像素占用的字节数。
一张图片（BitMap）占用的内存=图片长度*图片宽度*单位像素占用的字节数。

电脑上图片尺寸，单位是像素(px)。Android手机的屏幕分ldpi、mdpi、hdpi，甚至还有xhdpi，
对于mdpi（density=160）设备，1dp=1px。
对于hdpi（density=240）的设备，1dp=1.5px。
所以，把图片放在了res/drawable-mdpi文件夹下。而执行的Android设备屏幕属于hdpi，导致图片尺寸会扩大1.5倍。

Bitmap.Config是Bitmap的一个枚举内部类，它表示的就是每个像素点对ARGB通道值的存储方案。取值有以下四种：
ALPHA_8：每个像素占8位（1个字节），存储透明度信息，没有颜色信息。
RGB_565：没有透明度，R=5，G=6，B=5，，那么一个像素点占5+6+5=16位（2字节），能表示2^16种颜色。
ARGB_4444：由4个4位组成，即A=4，R=4，G=4，B=4，那么一个像素点占4+4+4+4=16位 （2字节），能表示2^16种颜色。
ARGB_8888：由4个8位组成，即A=8，R=8，G=8，B=8，那么一个像素点占8+8+8+8=32位（4字节），能表示2^24种颜色。

色深：顾名思义，就是"色彩的深度"，指是每一个像素点用多少bit来存储ARGB值，属于图片自身的一种属性。
色深可以用来衡量一张图片的色彩处理能力（即色彩丰富程度）。典型的色深是8-bit、16-bit、24-bit和32-bit等。
上述的Bitmap.Config参数的值指的就是色深。比如ARGB_8888方式的色深为32位，RGB_565方式的色深是16位。色深是数字图像参数。

位深度是指在记录数字图像的颜色时，计算机实际上是用每个像素需要的二进制数值位数来表示的。
当这些数据按照一定的编排方式被记录在计算机中，就构成了一个数字图像的计算机文件。
每一个像素在计算机中所使用的这种位数就是“位深度”，位深是物理硬件参数，主要用来存储。

举个例子：某张图片100像素*100像素 色深32位(ARGB_8888)，保存时位深度为24位，那么：
该图片在内存中所占大小为：100 * 100 * (32 / 8) Byte
在文件中所占大小为 100 * 100 * ( 24/ 8 ) * 压缩率 Byte


*/

@Suppress("UNUSED")
object InstanceOfPicture {

    //从文件读取图片
    //目标是获取一个长500，宽500的图片
    //decodeFileDescriptor
    fun test01(context: Context): Bitmap? {

        //先搞一张图片
        val rootFile = Environment.getExternalStorageDirectory()
        val imagePath =
            rootFile.absolutePath + File.separator + Environment.DIRECTORY_PICTURES + File.separator + "xty.jpg"
        val file = File(imagePath)
        if (!file.exists()) {
            LogUtil.default01("文件不存在")
            return null
        } else {
            LogUtil.default01("文件存在")
        }

        var fileInputStream: FileInputStream? = null

        try {
            fileInputStream = FileInputStream(file)
            LogUtil.default01(fileInputStream.toString())
            val options = BitmapFactory.Options()
            //该属性设置为true将不返回实际的bitmap，也不给其分配内存空间这样就避免内存溢出了。（返回null）但是允许我们查询图片的信息这其中就包括图片大小信息
            options.inJustDecodeBounds = true
            //从文件读取文件
            BitmapFactory.decodeFileDescriptor(fileInputStream.fd, null, options)
            //获取图片的宽度和高度
            val srcWidth = options.outWidth
            val srcHeight = options.outHeight
            var inSampleSize = 1
            if (srcWidth > 500 || srcHeight > 500) {
                inSampleSize = if (srcWidth > srcHeight) srcHeight / 500 else srcWidth / 500
            }

            options.inJustDecodeBounds = false
            options.inSampleSize = inSampleSize

            return BitmapFactory.decodeFileDescriptor(fileInputStream.fd, null, options)

        } catch (e: Exception) {
            LogUtil.fail()
            LogUtil.default01(e.message.toString())
            return null
        } finally {
            fileInputStream?.close()
        }

    }

    //
    fun test02(context: Context): Bitmap? {
        val rootFile = Environment.getExternalStorageDirectory()
        val imagePath =
            rootFile.absolutePath + File.separator + Environment.DIRECTORY_PICTURES + File.separator + "yuanyuan.jpg"
        var inputOutputStream: FileInputStream? = null
        return try {
            inputOutputStream = FileInputStream(imagePath)
            val options = BitmapFactory.Options()
             options.inJustDecodeBounds = true
         //  BitmapFactory.decodeStream(inputOutputStream,null,options)

//            val srcWidth = options.outWidth
//            val srcHeight = options.outHeight
//            var inSampleSize = 1
//            if (srcWidth > 500 || srcHeight > 500) {
//                inSampleSize = if (srcWidth > srcHeight) srcHeight / 500 else srcWidth / 500
//            }

          options.inJustDecodeBounds = false
            //options.inSampleSize = inSampleSize

            BitmapFactory.decodeStream(inputOutputStream,null,options)
        } catch (e: Exception) {
            null
        } finally {
            inputOutputStream?.close()
        }
    }

    fun test03(context: Context) {

    }

}


//